home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gekkan Dennou Club 145
/
Gekkan Dennou Club - 2000.6 Vol. 145 (Japan).7z
/
Gekkan Dennou Club - 2000.6 Vol. 145 (Japan) (Track 1).bin
/
tools
/
sharp
/
sxwork3.lzh
/
サンプル実用編
/
爆弾ゲーム
/
BOMB.C
< prev
next >
Wrap
Text File
|
1994-03-10
|
37KB
|
1,233 lines
/******************************************************************************
* bomb.c: 爆弾ゲームの処理関数
******************************************************************************
* Workroom SX-68K Sample Program Copyright 1994 SHARP
*
* 機能説明:
* セルの描画,マップの作成,タイマー処理,当たり判定などなどの処理を
* 行います。
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sxmemory.h> /* メモリマンを利用するときに必要 */
#include <event.h> /* イベントマンを利用するときに必要 */
#include <sxgraph.h> /* グラフ系マネージャを利用するときに必要 */
#include <window.h> /* ウィンドウマンを利用するときに必要 */
#include <dialog.h> /* ダイアログマンを利用するときに必要 */
#include <text.h> /* テキストマンを利用するときに必要 */
#include <task.h> /* タスクマンを利用するときに必要 */
#include "bomb.h" /* このプログラム固有のヘッダファイル */
/******************************************************************************
* getGrid(): マウスグリッドポインタがセルマップ上かどうかを調べる
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* LPoint lpt ポインタ座標
* CPoint *pcpt セルマップ上のグリッドへのポインタ
* 戻り値: BOOLEAN = TRUE: グリッドポインタはセルマップの中
* = FALSE: グリッドポインタはセルマップの外
* 注釈: セルマップ上であったなら、そのグリッドポインタを求める。
*/
BOOLEAN getGrid(ComVal *pcv, LPoint lpt, CPoint *pcpt)
{
Rect rc;
rc = pcv->windowPtr->graph.rect;
rc.d.top += MARGIN * 2 + INFO_HEIGHT;
rc.d.left += MARGIN;
rc.d.bottom -= MARGIN;
rc.d.right -= MARGIN;
if (!GMPtInRect(&rc, lpt))
return FALSE;
pcpt->x = (HIWORD(lpt) - MARGIN) / 16;
pcpt->y = (LOWWORD(lpt) - (MARGIN * 2 + INFO_HEIGHT)) / 16;
return TRUE;
}
/******************************************************************************
* drawCell(): セルマップの再描画処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void drawCell(ComVal *pcv)
{
int iX, iY;
int iValue;
LPoint lpt;
for (iY = 0; iY < pcv->gridY; iY++) {
/* 左端表示座標位置.ここからセルごとに右に書いていく */
for (iX = 0; iX < pcv->gridX; iX++) {
lpt = GRID(iX, iY);
/*** 開始前の場合 ***/
if (pcv->sTrends == IDT_BEFORE) {
drawPat3(pcv->btnImg[0], lpt);
continue;
}
/*** ゲーム開始後の場合 ***/
if (pcv->sTrends == IDT_BEGIN || pcv->sTrends == IDT_PLAYING) {
switch (pcv->fCheck[iY][iX]) {
case IDC_FLAG: /* 旗 */
drawMark(pcv, iX, iY, IDC_FLAG);
break;
case IDC_QMARK: /* ?マーク */
drawMark(pcv, iX, iY, IDC_QMARK);
break;
case IDC_FACE: /* 未オープン */
drawPat3(pcv->btnImg[0], lpt);
break;
case IDC_RBOM: /* 赤爆弾 */
drawPat3(pcv->btnImg[2], lpt);
break;
case IDC_CBOM: /* ばってん爆弾 */
drawPat3(pcv->btnImg[4], lpt);
break;
case IDC_OPEN: /* オープン済み */
/* 指定セルのステータスを取得する */
switch (iValue = pcv->fMap[iY][iX]) {
case IDV_PLAIN: /* 無印オープンセルの場合 */
drawPat3(pcv->btnImg[1], lpt);
break;
case IDV_BOM:
drawPat3(pcv->btnImg[3], lpt);
break;
default:
/* 数字オープンセルの場合 */
if (iValue >= IDV_VAL1 && iValue <= IDV_VAL8)
drawPat3(pcv->numImg[iValue - 1], lpt);
break;
}
break;
}
/*** ゲーム終了後 ***/
} else {
switch (pcv->fCheck[iY][iX]) {
case IDC_FLAG: /* 旗 */
drawMark(pcv, iX, iY, IDC_FLAG);
break;
case IDC_FACE: /* 未オープン */
drawPat3(pcv->btnImg[0], lpt);
break;
case IDC_RBOM: /* 赤爆弾 */
drawPat3(pcv->btnImg[3], lpt);
break;
case IDC_CBOM: /* ばってん爆弾 */
drawPat3(pcv->btnImg[4], lpt);
break;
default:
/* 指定セルのステータスを取得する */
switch (pcv->fMap[iY][iX]) {
case IDV_PLAIN: /* 無印オープンセルの場合 */
drawPat3(pcv->btnImg[1], lpt);
break;
case IDV_BOM: /* 爆弾オープンセルの場合 */
drawPat3(pcv->btnImg[2], lpt);
break;
default: /* 数字オープンセルの場合 */
drawPat3(pcv->numImg[pcv->fMap[iY][iX] - 1], lpt);
break;
}
break;
}
}
}
}
}
/******************************************************************************
* changeLevel(): セルマップのサイズと爆弾数を変更する
******************************************************************************
* 引数: int num 選択されたメニューアイテムの番号
* ComVal *pcv 共通変数へのポインタ
*/
void changeLevel(ComVal *pcv, int num)
{
switch (num) {
case 1: /* ビギナークラス */
pcv->gridY = pcv->gridX = pcv->bombNum = 10;
pcv->level = IDL_BEG; /* ゲームレベル */
break;
case 2: /* ミドルクラス */
pcv->gridY = 16;
pcv->gridX = 16;
pcv->bombNum = 40;
pcv->level = IDL_MID;
break;
case 3: /* エキスパートクラス */
pcv->gridY = 16;
pcv->gridX = 30;
pcv->bombNum = 99;
pcv->level = IDL_EXP;
break;
}
/* 再描画するウィンドウサイズ変更 */
WMSize(pcv->windowPtr, WSIZE(pcv->gridX, pcv->gridY), 0);
/* 再描画処理 */
regame(pcv);
}
/******************************************************************************
* enterDlg(): ベストタイム登録用ダイアログ作成
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void enterDlg(ComVal *pcv)
{
int i;
Rect rc;
Dialog dialog; /* ダイアログレコード */
Dialog *dialogPtr = &dialog; /* ダイアログポインタ(疑似ポインタ)*/
/* ベストタイム登録用ダイアログの表示位置 */
static Rect dlgPos = { DLG1_X, DLG1_Y, DLG1_X + DLG1_H, DLG1_Y + DLG1_V };
static Rect rcText = { 32 - 2, 48 - 2, 140 + 2, 60 + 2 };
/* SX-WINDOW ver2.0以上の場合は、ダイアログの表示位置を画面の中央に
配置するように補正する */
TSAdjustRect(&rc, &dlgPos, 16); /* 768*512の画面を基準に補正 */
dialogPtr = DMOpen(dialogPtr, &rc, NONTITLE, FALSE, WI_DLG << 4,
W_FRONT, FALSE, LONGWORD(1, TSGetID()), pcv->resDiEnt);
if (dialogPtr == NULL) {
DMError(D_CONFIRM, "タイアログが作成できません。");
return;
}
/* 編集可能テキストの文字列をクリアする */
setDItemText(dialogPtr, 1, NONTITLE);
WMShow(&dialogPtr->window); /* ダイアログを表示する */
GMSetGraph(&dialogPtr->window.graph);
GMAPage(G_PAGE0 | G_PAGE1); /* アクセスページを0と1ページにする */
GMForeColor(G_BLACK);
GMBackColor(G_LGRAY);
/* ダイアログタイトル */
GMShadowStrZ("ベストプレーヤーの登録", LONGWORD((DLG1_H - 11 * 12) / 2, 4));
GMShadowStrZ("プレーヤーの名前", LONGWORD(30, 32));
/* 名前入力欄 */
GMBackColor(G_WHITE);
GMShadowRect(&rcText);
DMDraw(dialogPtr);
while (1) {
i = DMControl(enterFilter);
if (i == 2) {
/* [確認]ボタンが押された */
/* 編集可能テキストの文字列を取得する */
getDItemText(dialogPtr, 1, pcv->player);
break;
}
}
GMBackColor(G_LGRAY);
DMClose(dialogPtr); /* ダイアログをクローズする */
}
/******************************************************************************
* enterFilter(): ダイアログ上のイベント処理
******************************************************************************
* 引数: Dialog *dlgPtr ダイアログポインタ
* Event *pev イベントレコードへのポインタ
* 戻り値: int 0以外: DMControlの返り値
*/
int enterFilter(Dialog *dlgPtr, Event *pev)
{
switch (pev->what) {
case E_KEYDOWN:
if (pev->whom.key.ascii == '\r')
return 2;
break;
case E_IDLE: /* アイドルイベント、その他のイベント */
default:
/* カーソルの点滅 */
TMIdle(dlgPtr->tEdit);
break;
}
return 0;
}
/******************************************************************************
* recordDlg(): ベストタイム表示用ダイアログ作成
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void recordDlg(ComVal *pcv)
{
int i;
char szScrName[TS_NAMEMAX], str[64];
FILE *fn;
Rect rc;
Dialog dialog; /* ダイアログレコード */
Dialog *dialogPtr = &dialog; /* ダイアログポインタ(疑似ポインタ)*/
/* ベストタイム表示用ダイアログの表示位置 */
static Rect dlgPos = { DLG2_X, DLG2_Y, DLG2_X + DLG2_H, DLG2_Y + DLG2_V };
/* SX-WINDOW ver2.0以上の場合は、ダイアログの表示位置を画面の中央に
配置するように補正する */
TSAdjustRect(&rc, &dlgPos, 16); /* 768*512の画面を基準に補正 */
dialogPtr = DMOpen(dialogPtr, &rc, NONTITLE, TRUE, WI_DLG << 4,
W_FRONT, FALSE, LONGWORD(2, TSGetID()), pcv->resDiRec);
if (dialogPtr == NULL) {
DMError(D_CONFIRM, "タイアログが作成できません。");
return;
}
strcpy(szScrName, pcv->myPath);
strcat(szScrName, "爆弾ゲーム.scr");
/* ベストタイム保持ファイルオープン */
fn = fopen(szScrName, "rb");
if (fn == NULL) {
strcpy(pcv->record[0], "999秒");
strcpy(pcv->record[1], "999秒");
strcpy(pcv->record[2], "999秒");
/* ファイルオープン成功なら */
} else {
/* レベルごとの文字列を取得する */
for (i = 0; i < 3; i++) {
fgets(pcv->record[i], BUFF_SIZE, fn);
pcv->record[i][strlen(pcv->record[i]) - 1] = 0;
}
fclose(fn);
}
GMSetGraph(&dialogPtr->window.graph);
GMAPage(G_PAGE0 | G_PAGE1); /* アクセスページを0と1ページにする */
GMForeColor(G_BLACK);
GMBackColor(G_LGRAY);
/* ダイアログタイトル */
GMShadowStrZ("ベストプレーヤー", LONGWORD((DLG2_H - 8 * 12) / 2, 4));
sprintf(str, "ビギナークラス %s\0", pcv->record[0]);
GMShadowStrZ(str, LONGWORD(10, 40));
sprintf(str, "ミドルクラス %s\0", pcv->record[1]);
GMShadowStrZ(str, LONGWORD(10, 60));
sprintf(str, "エキスパートクラス %s\0", pcv->record[2]);
GMShadowStrZ(str, LONGWORD(10, 80));
DMDraw(dialogPtr);
while (1) {
i = DMControl(recordFilter);
if (i == 1)
break;
}
DMClose(dialogPtr); /* ダイアログをクローズする */
}
/******************************************************************************
* recordFilter(): ダイアログ上のイベント処理
******************************************************************************
* 引数: Dialog *dlgPtr ダイアログポインタ
* Event *pev イベントレコードへのポインタ
* 戻り値: int 0以外: DMControlの返り値
*/
int recordFilter(Dialog *dlgPtr, Event *pev)
{
if (pev->what == E_KEYDOWN && pev->whom.key.ascii == '\r')
return 1;
return 0;
}
/******************************************************************************
* setDItemText(): ダイアログアイテムの編集可能テキストへの文字列の設定
******************************************************************************
* 引数: Dialog *dlgPtr ダイアログポインタ
* int num ダイアログのアイテム番号
* _LASCII str 設定するLASCII型文字列
*/
void setDItemText(Dialog *dlgPtr, int num, _LASCII str)
{
short type;
Rect rc;
Handle item;
/* ダイアログアイテムのハンドルを取得する */
DIGet(dlgPtr, num, &type, &item, &rc);
DITSet(type, item, str); /* 編集可能テキストに文字列を設定する */
}
/******************************************************************************
* getDItemText(): ダイアログアイテムの編集可能テキストの文字列の取得
******************************************************************************
* 引数: Dialog *dlgPtr ダイアログポインタ
* int num ダイアログのアイテム番号
* _LASCII str LASCII型文字列を格納するポインタ
*/
void getDItemText(Dialog *dlgPtr, int num, _LASCII str)
{
short type;
Rect rc;
Handle item;
/* ダイアログアイテムのハンドルを取得する */
DIGet(dlgPtr, num, &type, &item, &rc);
DITGet(type, item, str); /* 編集可能テキストの文字列を取得する */
str[str[0] + 1] = 0; /* 文字列の最後に0を付加する */
}
/******************************************************************************
* mountImgRes(): ビットイメージのハンドルを確保
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* 戻り値: BOOLEAN = TRUE: 正常終了
* = FALSE: 異常終了
*/
BOOLEAN mountImgRes(ComVal *pcv)
{
int i;
/* ハンドルを格納する配列の初期化 */
for (i = 0; i < 8; i++)
pcv->btnImg[i] = NULL;
for (i = 0; i < 8; i++)
pcv->numImg[i] = NULL;
for (i = 0; i < 4; i++)
pcv->bombImg[i] = NULL;
pcv->resDiEnt = NULL;
pcv->resDiRec = NULL;
/* "爆弾ゲーム.lb"をカレントリソースにする */
if (!loadResource(pcv))
return FALSE;
/* 各種フィールド用のイメージデータの取得 */
for (i = 0; i < 8; i++) {
pcv->btnImg[i] = TSRscGet('PAT3', 2000 + i);
if (pcv->btnImg[i] == NULL)
return FALSE;
}
/* 各種フィールド用のイメージデータの取得(1~8の番号のマス) */
for (i = 0; i < 8; i++) {
/* リソースハンドルを取得する */
pcv->numImg[i] = TSRscGet('PAT3', 1001 + i);
if (pcv->numImg[i] == NULL)
return FALSE;
}
/* 爆弾の個数を示すのイメージデータの取得 */
for (i = 0; i < 4; i++) {
/* リソースハンドルを取得する */
pcv->bombImg[i] = TSRscGet('PAT4', 1000 + i);
if (pcv->bombImg[i] == NULL)
return FALSE;
}
pcv->resDiEnt = TSRscGet('DITL', 1000);
if (pcv->resDiEnt == NULL)
return FALSE;
pcv->resDiRec = TSRscGet('DITL', 1001);
if (pcv->resDiRec == NULL)
return FALSE;
return TRUE;
}
/******************************************************************************
* loadResource(): ダイアログのリソースファイルを読み出す
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* 戻り値: BOOLEAN = TRUE: 読み込み成功
* = FALSE: 読み込み失敗
*/
BOOLEAN loadResource(ComVal *pcv)
{
int errCode;
Handle resHdl;
Task task; /* タスク管理レコード */
char drv[2], path[65], node[19], ext[5];
char fWork[TS_NAMEMAX];
TSGetTdb(&task, TS_OWN); /* タスク管理レコードを取得する */
strsfn(task.name, drv, path, node, ext); /* タスク名を分解する */
strmfn(fWork, drv, path, "", ""); /* 検索パスを作成する */
/* リソースファイルを検索する */
errCode = TSSearchFile("爆弾ゲーム.LB", fWork, fWork);
if (errCode < 0) { /* リソースファイルが見付からない */
DMError(D_CONFIRM, "リソースファイル「爆弾ゲーム.LB」が\r"
"見付かりません。");
return FALSE;
}
resHdl = TSResOpen(fWork); /* リソースのオープン */
if (resHdl == NULL) {
DMError(D_CONFIRM, "リソースファイル「爆弾ゲーム.LB」が\r"
"オープンできません。");
return FALSE;
}
errCode = TSResLoad();
if (errCode < 0) {
DMError(D_CONFIRM, "リソースファイルが読み込めません。");
/* カレントリソースの削除とリソースファイルのクローズ
-->TSResDisposeではクローズしないのでダメ!*/
TSResRemove();
return FALSE;
}
return TRUE;
}
/******************************************************************************
* drawPat3(): パターンハンドル('PAT3')の描画
******************************************************************************
* 引数: RectImg **phdl 'PAT3'のハンドル
* LPoint lpt 表示座標
*/
void drawPat3(RectImg **phdl, LPoint lpt)
{
MMHdlLock(phdl); /* ハンドルをロック */
GMPutRImg(*phdl, lpt); /* レクタングルイメージを描画 */
MMHdlUnlock(phdl); /* ハンドルのロックを解除 */
}
/******************************************************************************
* drawPat4(): マスク付パターンハンドル('PAT4')の描画
******************************************************************************
* 引数: RectImg **phdl 'PAT4'のハンドル
* LPoint lpt 表示座標
*/
void drawPat4(RectImg **phdl, LPoint lpt)
{
int lastAP;
Rect rc;
RectImg *iptr;
MMHdlLock(phdl); /* ハンドルをロック */
iptr = *phdl;
rc = iptr->bounds;
GMSlideRect(&rc, lpt);
/* アクセスページを0~2ページにする */
lastAP = GMAPage(G_PAGE0 | G_PAGE1 | G_PAGE2);
GMPlotImg(iptr->data, &rc, 3 << 8); /* image のプット */
GMAPage(lastAP);
MMHdlUnlock(phdl); /* ハンドルのロックを解除 */
}
/******************************************************************************
* getParam():
******************************************************************************
* 引数: char **tbuff コマンドラインのアドレステーブル
* 注釈: '-C?'(ゲームクラス設定)のオプションスイッチをサポート
*/
void getParam(ComVal *pcv, char **tbuff)
{
int i, ct;
char *cp;
ct = (int) *tbuff++;
if (ct > 0) { /* オプションスイッチの有無 */
for (i = 0; i < ct; i++) {
cp = *tbuff++;
if (*cp == '-' || *cp == '/') {
cp++;
switch (*cp++) {
case 'C': /* ゲームレベルの設定 */
case 'c':
switch (*cp++) {
case '0': /* ビギナークラス */
pcv->gridY = 10;
pcv->gridX = 10;
pcv->bombNum = 10;
pcv->level = IDL_BEG; /* ゲームレベル */
break;
case '1': /* ミドルクラス */
pcv->gridY = 16;
pcv->gridX = 16;
pcv->bombNum = 40;
pcv->level = IDL_MID;
break;
case '2': /* エキスパートクラス */
pcv->gridY = 16;
pcv->gridX = 30;
pcv->bombNum = 99;
pcv->level = IDL_EXP;
break;
}
break;
}
}
}
}
}
/******************************************************************************
* initMap(): セルマップの初期化
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* CPoint *pcpt
*/
void initMap(ComVal *pcv, CPoint *pcpt)
{
int di = 0, dj = 0, dk = 0;
register int i;
register int iLim, iBom;
register int iX, iY;
/* 爆弾の配置 */
srand(EMSysTime() + LONGWORD(pcpt->x, pcpt->y));
iLim = (pcv->gridX * pcv->gridY) - 1;
for (i = 0; i < pcv->bombNum; i++) {
iBom = rand();
iBom %= iLim;
iX = iBom % pcv->gridX;
iY = iBom / pcv->gridX;
dk++;
if (pcv->fMap[iY][iX] == IDV_BOM) {
i--;
di++;
continue;
}
if (iX == pcpt->x && iY == pcpt->y) {
i--;
dj++;
continue;
}
pcv->fMap[iY][iX] = IDV_BOM;
}
/* 爆弾セル以外のボリューム設定 */
for (iY = 0; iY < pcv->gridY; iY++)
for (iX = 0; iX < pcv->gridX; iX++)
if (pcv->fMap[iY][iX] != IDV_BOM) /* 爆弾セルでなければ */
setValue(pcv, iX, iY); /* セルボリューム設定 */
}
/******************************************************************************
* clearGame(): ゲームクリア処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void clearGame(ComVal *pcv)
{
int iX, iY;
/**** CLEAR!!!****/
pcv->sTrends = IDT_CLEAR; /* ゲーム進行状況フラグ = ゲームクリアー */
/* 残ったセルに旗を立てる */
for (iY = 0; iY < pcv->gridY; iY++) {
for (iX = 0; iX < pcv->gridX; iX++) {
if (pcv->fCheck[iY][iX] != IDC_OPEN) {
/* 旗を描く */
drawPat3(pcv->btnImg[6], GRID(iX, iY));
pcv->fCheck[iY][iX] = IDC_FLAG;
}
}
}
/* 残り爆弾数消去 */
pcv->restFlag = 0;
drawZan(pcv);
/* ベストタイム保持処理 */
bestTime(pcv);
}
/******************************************************************************
* regame(): 再ゲーム開始処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void regame(ComVal *pcv)
{
int iX, iY;
pcv->restCell = pcv->gridX * pcv->gridY; /* 未処理セル数 */
pcv->restFlag = pcv->bombNum; /* 残り旗数 */
pcv->sTrends = IDT_BEFORE; /* ゲーム進行状況(開始前) */
pcv->seconds = 0; /* 経過タイム */
/* セルマップの初期化 */
for (iY = 0; iY < pcv->gridY; iY++) {
for (iX = 0; iX < pcv->gridX; iX++) {
pcv->fMap[iY][iX] = IDV_PLAIN;
pcv->fCheck[iY][iX] = IDC_FACE;
}
}
addUpdate(pcv->windowPtr, NULL); /* ウィンドウ内全体を再描画する */
}
/******************************************************************************
* bestTime(): ベストタイム変更処理
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void bestTime(ComVal *pcv)
{
int iTime, i;
FILE *fn;
char szScrName[TS_NAMEMAX];
strcpy(szScrName, pcv->myPath);
strcat(szScrName, "爆弾ゲーム.scr");
/* ベストタイム保持ファイルオープン */
fn = fopen(szScrName, "rb");
if (fn == NULL) {
/* デフォルトのデータを書き込む */
strcpy(pcv->record[0], "999秒");
strcpy(pcv->record[1], "999秒");
strcpy(pcv->record[2], "999秒");
/* ファイルオープン成功なら */
} else {
/* レベルごとの文字列を取得する */
for (i = 0; i < 3; i++) {
fgets(pcv->record[i], BUFF_SIZE, fn);
pcv->record[i][strlen(pcv->record[i]) - 1] = 0;
}
fclose(fn); /* 現在のファイルをクローズ */
}
/* 現在のゲームレベルでのベストタイムを参照 */
iTime = atoi(pcv->record[pcv->level]);
/* 今回のタイムがベストタイムかどうか */
/* ベストじゃなければリターン */
if (pcv->seconds >= iTime)
return;
/* ベストタイム保持用のダイアログを作成 */
enterDlg(pcv);
fn = fopen(szScrName, "wb"); /* 新たに同名ファイルを作成 */
if (fn == NULL)
return;
/* ベストタイム更新! スコアファイルの書き換え */
sprintf(pcv->record[pcv->level], "%3d秒 %s\0", pcv->seconds, &pcv->player[1]);
for (i = 0; i < 3; i++) {
fwrite((unsigned char *) pcv->record[i], sizeof(char), strlen(pcv->record[i]), fn);
fwrite((unsigned char *) "\n", sizeof(char), 1, fn);
}
/* スコアファイルをクローズ */
fclose(fn);
/* ベストタイム表示ダイアログ作成 */
recordDlg(pcv);
}
/******************************************************************************
* drawBitmap(): 指定位置のセルを開く
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* CPoint *pcpt セル位置(x,y)へのポインタ
*/
void drawBitmap(ComVal *pcv, CPoint *pcpt)
{
unsigned char iValue;
GMSetGraph(&pcv->windowPtr->graph); /* 自分をカレントグラフにする */
iValue = pcv->fMap[pcpt->y][pcpt->x]; /* 指定セルのステータス */
switch (iValue) {
case IDV_BOM:
/* ゲームオーバー! */
openAllBomb(pcv, pcpt);
break;
case IDV_VAL1:
case IDV_VAL2:
case IDV_VAL3:
case IDV_VAL4:
case IDV_VAL5:
case IDV_VAL6:
case IDV_VAL7:
case IDV_VAL8:
drawPat3(pcv->numImg[iValue - 1], GRID(pcpt->x, pcpt->y));
pcv->restCell--; /* 未処理セル数を1つ減らす */
pcv->fCheck[pcpt->y][pcpt->x] = IDC_OPEN; /* オープン済 */
break;
case IDV_PLAIN:
/* セルを開く */
safetyZone(pcv, pcpt);
break;
}
}
/******************************************************************************
* drawMark(): 旗と?マークの描画、描き換えを行う
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int iX セル位置
* int iY
* char fMark 書き換えるセルの属性
*/
void drawMark(ComVal *pcv, int iX, int iY, unsigned char fMark)
{
LPoint lpt;
GMSetGraph(&pcv->windowPtr->graph); /* 自分をカレントグラフにする */
/* 指定セルの位置を取得する */
lpt = GRID(iX, iY);
switch (fMark) {
case IDC_FACE: /* 未処理状態 */
drawPat3(pcv->btnImg[0], lpt); /* セルを描き換え */
break;
case IDC_FLAG: /* 旗 */
drawPat3(pcv->btnImg[6], lpt);
break;
case IDC_QMARK: /* ?マーク */
drawPat3(pcv->btnImg[5], lpt);
break;
}
}
/******************************************************************************
* setValue(): セルボリュームの設定(爆弾セル以外)
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int iX セル位置
* int iY
*/
void setValue(ComVal *pcv, int iX, int iY)
{
int i, j, cx, cy;
/* 自分の周囲セルの爆弾数をカウントして、その数値を自分のボリュームとする */
for (i = -1; i <= 1; i++) {
cy = iY + i;
for (j = -1; j <= 1; j++) {
cx = iX + j;
/* 自分セルでなく、セルマップからはみださないことが検索条件 */
if (cx < 0 || cx >= pcv->gridX || cy < 0 || cy >= pcv->gridY)
continue;
if (pcv->fMap[cy][cx] == IDV_BOM)
pcv->fMap[iY][iX] += 1;
}
}
}
/******************************************************************************
* safetyZone(): 広範囲の爆弾のないエリア(SafeZone)を開く
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* CPoint *pcpt セル位置へのポインタ
*/
void safetyZone(ComVal *pcv, CPoint *pcpt)
{
int iCheck;
CPoint cpt;
/* 指定のセルが盤からはみ出していたらリターン */
if (pcpt->x < 0 || pcpt->x >= pcv->gridX || pcpt->y < 0 || pcpt->y >= pcv->gridY)
return;
/* 自分のセルがすでに開いてる、または旗が立っていたらリターン */
iCheck = pcv->fCheck[pcpt->y][pcpt->x];
if (iCheck == IDC_OPEN || iCheck == IDC_FLAG)
return;
/* 自分セルを開く */
openCell(pcv, pcpt);
/* 自分のセルが数字だったらリターン */
if (pcv->fMap[pcpt->y][pcpt->x] != IDV_PLAIN)
return;
cpt.x = pcpt->x - 1;
cpt.y = pcpt->y - 1;
safetyZone(pcv, &cpt);
cpt.x++;
safetyZone(pcv, &cpt);
cpt.x++;
safetyZone(pcv, &cpt);
cpt.x -= 2;
cpt.y++;
safetyZone(pcv, &cpt);
cpt.x += 2;
safetyZone(pcv, &cpt);
cpt.x -= 2;
cpt.y++;
safetyZone(pcv, &cpt);
cpt.x++;
safetyZone(pcv, &cpt);
cpt.x++;
safetyZone(pcv, &cpt);
}
/******************************************************************************
* openCell(): 指定されたマスを無条件に開く
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* CPoint *pcpt セル位置へのポインタ
*/
void openCell(ComVal *pcv, CPoint *pcpt)
{
unsigned int iValue;
LPoint lpt;
GMSetGraph(&pcv->windowPtr->graph); /* 自分をカレントグラフにする */
/* 指定セルの位置を取得する */
lpt = GRID(pcpt->x, pcpt->y);
/* 指定されたマスのステータスを求める */
iValue = pcv->fMap[pcpt->y][pcpt->x];
/* 指定されたマスをオープン(描画)する */
switch (iValue) {
case IDV_PLAIN:
drawPat3(pcv->btnImg[1], lpt);
pcv->restCell--; /* 未処理セル数を1つ減らす */
pcv->fCheck[pcpt->y][pcpt->x] = IDC_OPEN; /* オープン済 */
break;
case IDV_VAL1:
case IDV_VAL2:
case IDV_VAL3:
case IDV_VAL4:
case IDV_VAL5:
case IDV_VAL6:
case IDV_VAL7:
case IDV_VAL8:
drawPat3(pcv->numImg[iValue - 1], lpt);
pcv->restCell--; /* 未処理セル数を1つ減らす */
pcv->fCheck[pcpt->y][pcpt->x] = IDC_OPEN; /* オープン済 */
break;
}
}
/******************************************************************************
* openAllBomb(): すべての爆弾のセルを開く
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* CPoint *pcpt 中心とするセル位置へのポインタ
*/
void openAllBomb(ComVal *pcv, CPoint *pcpt)
{
int val;
val = pcv->fMap[pcpt->y][pcpt->x]; /* 指定セルのステータス */
if (val == IDV_BOM) { /* 爆弾に当たったか? */
/* 自分のセルをオープン */
drawPat3(pcv->btnImg[3], GRID(pcpt->x, pcpt->y));
pcv->fCheck[pcpt->y][pcpt->x] = IDC_RBOM;
}
searchMesh(pcv, pcpt); /* 放射状に残りのを爆破する */
/* ゲーム停止(終了)のためのフラグ等の変更 */
pcv->sTrends = IDT_OVER;
}
/******************************************************************************
* searchMesh(): 放射状マスサーチ(爆弾セルを開く)
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* CPoint *pcpt 中心とするセル位置へのポインタ
*/
void searchMesh(ComVal *pcv, CPoint *pcpt)
{
int i, j, x, y, cx, cy;
x = pcpt->x;
y = pcpt->y;
cx = pcv->gridX - x - 1;
cx = (cx > x) ? cx : x; /* 横方向の最大ループ回数 */
cy = pcv->gridY - y - 1;
cy = (cy > y) ? cy : y; /* 縦方向のループ回数 */
cx = (cx > cy) ? cx : cy; /* 最大のループ回数 */
for (i = 1; i < cx + 1; i++) {
for (j = x + 1; j < x + i + 1; j++) /* 右上横 */
openBomb(pcv, j, y - i);
for (j = x - 1; j > x - i - 1; j--) /* 左下横 */
openBomb(pcv, j, y + i);
for (j = y; j > y - i; j--) /* 右上縦 */
openBomb(pcv, x + i, j);
for (j = y; j < y + i; j++) /* 左下縦 */
openBomb(pcv, x - i, j);
for (j = x; j < x + i; j++) /* 右下横 */
openBomb(pcv, j, y + i);
for (j = x; j > x - i; j--) /* 左上横 */
openBomb(pcv, j, y - i);
for (j = y + 1; j < y + i + 1; j++) /* 右下縦 */
openBomb(pcv, x + i, j);
for (j = y - 1; j > y - i - 1; j--) /* 左上縦 */
openBomb(pcv, x - i, j);
}
}
/******************************************************************************
* openBomb(): 爆弾をオープン
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int iX 中心とするセル位置
* int iY
*/
void openBomb(ComVal *pcv, int iX, int iY)
{
unsigned char iValue, iCheck;
LPoint lpt;
/* マップ外の座標なら無視 */
if (iX < 0 || iX >= pcv->gridX || iY < 0 || iY >= pcv->gridY)
return;
iValue = pcv->fMap[iY][iX];
iCheck = pcv->fCheck[iY][iX];
lpt = GRID(iX, iY);
/* 未処理の爆弾なら */
if (iValue == IDV_BOM && iCheck == IDC_FACE) {
drawPat3(pcv->btnImg[2], lpt); /* オープン */
pcv->fCheck[iY][iX] = IDC_OPEN;
/* 旗が間違って立っていたら */
} else if (iValue != IDV_BOM && iCheck == IDC_FLAG) {
drawPat3(pcv->btnImg[4], lpt); /* ばってん爆弾 */
pcv->fCheck[iY][iX] = IDC_CBOM;
}
}
/******************************************************************************
* timeCounter(): 経過秒数表示処理を行う
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* int iX 中心とするセル位置
* int iY
*/
void timeCounter(ComVal *pcv)
{
int mints, iSec, newtime;
CPoint cpt;
if (pcv->sTrends == IDT_PLAYING) { /* ゲーム進行中なら */
newtime = EMSysTime(); /* 現在のシステム時間を取得する */
mints = (newtime - pcv->oldTime) / 100;
if (mints >= 1) { /* 前回より1秒以上経過したら */
pcv->seconds += mints;
iSec = pcv->seconds % 10000;
/* タイムオーバー */
if (pcv->seconds > TIME_LIMIT) {
TSErrDialogN(D_CONFIRM, "タイムオーバーです。");
/* フィールドの中心 */
cpt.x = pcv->gridX / 2;
cpt.y = pcv->gridY / 2;
openAllBomb(pcv, &cpt);
return;
}
drawTime(pcv);
pcv->oldTime = newtime; /* 前回のシステム時間更新 */
}
} else if (pcv->sTrends == IDT_BEGIN) { /* 開始時なら */
pcv->oldTime = EMSysTime(); /* 開始システム時間を取得する */
/* 1/100秒単位で返ってくるので注意! */
pcv->sTrends = IDT_PLAYING; /*ゲーム進行中*/
}
}
/******************************************************************************
* drawZan(): 残り旗数の描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void drawZan(ComVal *pcv)
{
int sc, tc, i;
int lastFC, lastFK, lastFF, lastFM;
Point pt;
Rect rc;
static Rect rcAll = { 0, 0, 1024, 1024 };
/* 残数エリアの全体のレクタングル */
rc.l.l_t = LONGWORD(MARGIN, MARGIN + INFO_HEIGHT - 24 - 1);
rc.l.r_b = LONGWORD(pcv->windowPtr->graph.rect.d.right - MARGIN, MARGIN + INFO_HEIGHT);
GMClipRect(&rc);
lastFC = GMForeColor(G_LGRAY);
rc.d.top++;
GMFillRect(&rc);
/* ゲームがクリアされているか? */
if (pcv->sTrends == IDT_CLEAR) {
/* おめでとうの表示 */
pt.p.x = rc.d.left + ((rc.d.right - rc.d.left) / 2) - (8 * 16 / 2);
pt.p.y = rc.d.top;
GMForeColor(G_RED); /* 赤 */
lastFM = GMFontMode(G_PSET);
lastFF = GMFontFace(G_BOLD | G_ITALIC); /* 斜体強調 */
lastFK = GMFontKind(G_ROM16); /* 24dot ROM font */
GMMove(pt.x_y);
GMDrawStrZ("CLEAR!!!");
GMFontFace(lastFF);
GMFontKind(lastFK);
GMFontMode(lastFM);
} else {
/* 爆弾残数の表示 */
if (pcv->restFlag >= 0) {
sc = pcv->restFlag / 10; /* 10の位の数 */
tc = pcv->restFlag % 10; /* 1の位の数 */
pt.p.x = rc.d.left;
pt.p.y = rc.d.bottom - 24;
for (i = 0; i < sc; i++) {
/* 10の位を描画する */
drawPat4(pcv->bombImg[1], pt.x_y);
pt.p.x += 24;
}
pt.p.y = rc.d.bottom - 16;
for (i = 0; i < tc; i++) {
/* 1の位を描画する */
drawPat4(pcv->bombImg[0], pt.x_y);
pt.p.x += 16;
}
} else {
/* マイナスの場合 */
sc = abs(pcv->restFlag) / 10; /* 10の位の数 */
tc = abs(pcv->restFlag) % 10; /* 1の位の数 */
pt.p.x = rc.d.left;
pt.p.y = rc.d.bottom - 24;
for (i = 0; i < sc; i++) {
/* 10の位を描画する */
drawPat4(pcv->bombImg[3], pt.x_y);
pt.p.x += 24;
}
pt.p.y = rc.d.bottom - 16;
for (i = 0; i < tc; i++) {
/* 1の位を描画する */
drawPat4(pcv->bombImg[2], pt.x_y);
pt.p.x += 16;
}
}
}
GMClipRect(&rcAll);
GMForeColor(lastFC);
}
/******************************************************************************
* drawTime(): 経過時間の描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void drawTime(ComVal *pcv)
{
int lastFC, lastBC;
char str[16];
static Rect rctmmg = {
TMMGX, TMMGY + MARGIN, TMMGX + TMWIDE, TMMGY + TMHEIGHT + MARGIN
};
lastBC = GMBackColor(G_WHITE);
lastFC = GMForeColor(G_BLACK);
GMShadowRect(&rctmmg);
sprintf(str, "%4d\0", pcv->seconds);
GMMove(LONGWORD(TMMGX + 2, TMMGY + 2 + MARGIN)); /* フレーム内文字の座標 */
GMDrawStrZ(str);
GMBackColor(lastBC);
GMForeColor(lastFC);
}
/******************************************************************************
* drawRgBtn(): 再ゲームボタンの描画
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
*/
void drawRgBtn(ComVal *pcv)
{
Point pt;
/* 再ゲームボタンのレクタングル */
static Rect rcBtn = { 0, 0, RBTNWIDE, RBTNHEIGHT };
/* 再設定ボタンの表示座標を設定 */
pt.p.x = pcv->windowPtr->graph.rect.d.right - (RBTNMGX + RBTNWIDE);
pt.p.y = pcv->windowPtr->graph.rect.d.top + MARGIN + RBTNMGY;
/* 再設定ボタンのレクタングルを設定(参照用) */
pcv->rcReplay = rcBtn;
GMSlideRect(&pcv->rcReplay, pt.x_y);
drawPat3(pcv->btnImg[7], pt.x_y);
}
/******************************************************************************
* checkPctBtn(): ピクチャーボタンのチェック
******************************************************************************
* 引数: ComVal *pcv 共通変数へのポインタ
* Rect *prc ピクチャーボタンのレクタングルへのポインタ
* LPoint lpt ポインタ座標(ローカル座標系)
* 戻り値: BOOLEAN = TRUE: ボタンが押された
* = FALSE: ボタンは押されてない
*/
BOOLEAN checkPctBtn(ComVal *pcv, Rect *prc, LPoint lpt)
{
BOOLEAN ret = TRUE;
if (!GMPtInRect(prc, lpt))
return FALSE;
revFillRect(prc);
/* マウスボタンが離されるまでループ */
while (EMLStill()) {
lpt = EMMSLoc();
if (GMPtInRect(prc, lpt)) {
/* ボタン内にカーソルが移動 */
if (!ret) {
/* ボタンが押されてなければフレーム内を反転 */
revFillRect(prc);
ret = TRUE;
}
} else {
/* ボタン外にカーソルが移動 */
if (ret) {
/* ボタンが押されていたならフレーム内を反転 */
revFillRect(prc);
ret = FALSE;
}
}
}
/* マウスボタンが離された場合の処理 */
if (ret)
/* ボタンが押されていればフレーム内を戻す */
revFillRect(prc);
/* ボタンが離された場所をチェック */
if (!GMPtInRect(prc, lpt))
return FALSE;
return ret;
}
/******************************************************************************
* revFillRect(): レクタングル全体の反転
******************************************************************************
* 引数: Rect *prc 反転するレクタングルへのポインタ
*/
void revFillRect(Rect *prc)
{
int lastAP, lastFC, lastPM;
/* アクセスページを0と1ページにする */
lastAP = GMAPage(G_PAGE0 | G_PAGE1);
lastPM = GMPenMode(G_XOR);
lastFC = GMForeColor(G_BLACK);
GMFillRect(prc);
GMForeColor(lastFC);
GMPenMode(lastPM);
GMAPage(lastAP);
}
/******************************************************************************
* revFrameRect(): レクタングルのフレームを反転
******************************************************************************
* 引数: Rect *prc 反転するレクタングルへのポインタ
*/
void revFrameRect(Rect *prc)
{
int lastAP, lastFC, lastPM;
/* アクセスページを0と1ページにする */
lastAP = GMAPage(G_PAGE0 | G_PAGE1);
lastPM = GMPenMode(G_XOR);
lastFC = GMForeColor(G_BLACK);
GMFrameRect(prc);
GMForeColor(lastFC);
GMPenMode(lastPM);
GMAPage(lastAP);
}